# Vitest

A ferramenta de testes mais rápida!

# Antes de começar

Assim como no jest para utilizarmos o Vitest precisamos instalar o VueTestUtils, uma ferramenta que nos ajuda por meio de helpers e funcionalidades a testar e montar nossos componentes.

pode ser utilizado yarn, npm ou pnpm

npm i @vue/test-utils

apos a instalação do VueTestUtils, vamos instalar o Vitest

npm i -D vitest

# Oque é o Vitest ?

O Vitest é uma ferramenta de testes que utiliza o Vite como base, e por isso é muito mais rápida que o Jest, e também é muito mais simples de configurar.

# Configuração do Vitest

Para rodar os testes é necessário adicionar o seguinte script no package.json:

{
  "scripts": {
    "test": "vitest",
    "coverage": "vitest run --coverage"
  }
}

# Como utilizar o Vitest ?

Para criar um teste com o Vitest, basta criar um arquivo com a extensão .test.ts ou .spec.ts se o seu projeto é vue + typescript dentro da pasta de testes, e dentro do arquivo, basta importar o método test do Vitest e criar um teste.

import { shallowMount } from "@vue/test-utils";
import HelloWorld from "@/components/HelloWorld.vue";
import { describe, it, expect } from "vitest";

describe("HelloWorld.vue", () => {
  it("renders props.msg when passed", () => {
    const msg = "new message";

    const wrapper = shallowMount(HelloWorld, {
      propsData: { msg }
    });

    expect(wrapper.text()).toMatch(msg);
  });
});

Assim como no Jest o Vitest também possui o describe e o it, e também o expect, que é o que utilizamos para fazer as asserções.

O describe é utilizado para agrupar os testes, e o it é utilizado para criar um teste, e o expect é utilizado para fazer as asserções.

Depois de criar o teste, basta rodar o comando:

npm run test

# Testando componentes

Depois de entender o básico do Vitest, vamos criar um teste para um componente, para isso vamos criar um componente chamado Button.vue dentro da pasta components, e vamos criar um teste para ele.

Vamos criar um componente chamado Button.vue dentro da pasta components, e vamos criar um teste para ele.

<template>
  <div>
    <button data-testid="increment-count-button" @click="count++">
      Click me
    </button>
    <span>Count: {{ message }}</span>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "Button",
  data() {
    return {
      count: 0
    };
  },

  computed: {
    message() {
      return `Count: ${this.count}`;
    }
  },

  methods: {
    increment() {
      this.count++;
    }
  }
});
</script>

Agora vamos criar um teste para esse componente, para isso vamos criar um arquivo chamado Button.test.ts dentro da pasta tests, e vamos criar um teste para ele.

import Vue from "vue";
import { shallowMount, Wrapper } from "@vue/test-utils";

import { describe, it, expect } from "vitest";
import Button from "@/components/Button.vue";

interface IButton extends Vue {
  message: string;
  increment: () => void;
}

describe("Button.vue", () => {
  it("should render props.msg when passed", () => {
    const wrapper = shallowMount(Button, {
      propsData: {
        msg: "new message"
      }
    }) as Wrapper<IButton>;

    expect(wrapper.find("button").text()).toMatch("Click me");
  });

  it("should increment count when button is clicked", async () => {
    const wrapper = shallowMount(Button);

    await wrapper.find("button").trigger("click");

    expect(wrapper.vm.message).toBe("Count: 1");
  });
});

Que teste grande não é ? Mas vamos entender o que está acontecendo.

Primeiro vamos entender o que é o shallowMount, o shallowMount é utilizado para montar o componente, e ele recebe como parâmetro o componente que queremos montar, e também podemos passar o propsData, que é utilizado para passar os props para o componente.

Depois de montar o componente, podemos utilizar o find para encontrar um elemento dentro do componente, e também podemos utilizar o trigger para disparar um evento, e também podemos utilizar o vm para acessar os dados do componente.

# Vamos entender mais afundo o que está acontecendo no teste

Porque fizemos uma interface para o componente ?

Porque o componente não tem tipagem, e para que possamos acessar os dados do componente, precisamos tipar o componente, e para isso criamos uma interface para o componente.

interface IButton extends Vue {
  message: string;
  increment: () => void;
}

Estendemos a interface do Vue para que o componente tenha acesso a todos os métodos e propriedades do Vue. E também criamos uma interface para o componente, e dentro dessa interface criamos as computeds e methods que existem no nosso componente.

shallowMount é utilizado para montar o componente ?

Sim, o shallowMount é utilizado para montar o componente, e ele recebe como parâmetro o componente que queremos montar, e também podemos passar as props, mocks e tudo relacionado ao componente que estamos testando.

const wrapper = shallowMount(Button, {
  propsData: {
    msg: "new message"
  }
}) as Wrapper<IButton>;

Caso seu componente tenha contatos com Vuex ou Vuetify, você pode passar os mocks para o shallowMount, e assim você consegue testar o componente e suas dependências.

import { createLocalVue, shallowMount, Wrapper } from "@vue/test-utils";

const localVue = createLocalVue();

localVue.use(Vuetify);
localVue.use(Vuex);

describe("Button.vue", () => {
  const wrapper = shallowMount(Button, {
    localVue,
    propsData: {
      msg: "new message"
    }
  }) as Wrapper<IButton>;

  // Teste...
});

Dessa maneira, você consegue testar o componente com as dependências do vuex como chamadas na store, e também consegue testar o componente com o vuetify como os breaking points.

Como acessamos os dados do componente ?

Para acessar os dados do componente, podemos utilizar o vm, e para ter acesso a todas as propriedades do componente, precisamos tipar o componente, e para isso criamos uma interface para o componente.

# Dando um passo além

# Testando renderização do componente utilizando data-testid

Para testar a renderização do componente, podemos utilizar o data-testid, e para isso precisamos adicionar o data-testid no elemento que queremos testar.

<template>
  <div>
    <button data-testid="increment-count-button" @click="count++">
      Click me
    </button>
    <span>Count: {{ message }}</span>
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "Button",
  data() {
    return {
      count: 0
    };
  },

  computed: {
    message() {
      return `Count: ${this.count}`;
    }
  },

  methods: {
    increment() {
      this.count++;
    }
  }
});
</script>

Depois de adicionar o data-testid no elemento, podemos utilizar o find para encontrar o elemento, e também podemos utilizar o trigger para disparar um evento.

import Vue from "vue";

import { describe, it, expect } from "vitest";
import { shallowMount, Wrapper } from "@vue/test-utils";

import Button from "@/components/Button.vue";

interface IButton extends Vue {
  message: string;
  increment: () => void;
}

const DATA_TEST_ID = {
  INCREMENT_COUNT_BUTTON: "[data-testid='increment-count-button']"
};

describe("Button.vue", () => {
  it("should render props.msg when passed", () => {
    const wrapper = shallowMount(Button, {
      propsData: {
        msg: "new message"
      }
    }) as Wrapper<IButton>;

    expect(wrapper.find(DATA_TEST_ID.INCREMENT_COUNT_BUTTON).text()).toMatch(
      "Click me"
    );
  });

  it("should increment count when button is clicked", async () => {
    const wrapper = shallowMount(Button);

    await wrapper.find(DATA_TEST_ID.INCREMENT_COUNT_BUTTON).trigger("click");

    expect(wrapper.vm.message).toBe("Count: 1");
  });
});

Usando o data-testid, além de facilitar encontrar o elemento que você deseja testar, você também auxilia na criação de testes e2e(Cypress), pois você consegue identificar os elementos que você deseja testar.